import { defHttp } from '/@/utils/http/axios';
import { UploadFileParams } from '/#/axios';
import { ModalFunc } from 'ant-design-vue/es/modal/confirm';
import { ActionItemModel, DelBatchType, BtnEventContext, ApiSourceParam } from '../types/index';
import { isNullOrUnDef } from '/@/utils/is';
import { toJson } from '/@/utils';
import QueryString from 'qs';
import dayjs from 'dayjs';

import { ExclamationCircleFilled } from '@ant-design/icons-vue';
import { h } from 'vue';

import { useMessage } from '/@/hooks/web/useMessage';
import { downloadByData, downloadByApiUrl, commonDownFile } from '/@/utils/file/download';

import { TableActionType } from '/@/components/Table';

import { commonBatchApi, commonRemoveApi, ModelIds } from '/@/api/config-center/model-design';
import { deleteFlowProcessApi, deleteTransferFlowApi } from '/@/api/flow/flow';
import { getResourceInfo } from '/@/api/admin/resoure';

const messageFn = useMessage();
const { createMessage, createConfirm } = messageFn;
enum ApiType {
  LIST = '0',
  FILE_UPLOAD = '1',
  FILE_EXPORT = '2',
}
const callbackFn = {};

/**
 *
 * @param param as obj
 * @returns
 */
export const getRealApi = async ({
  params = {},
  apiCode,
  callbackFn = 'reload',
  callbacks = {},
  isCustom = false,
}: ApiSourceParam) => {
  const ret = await getResourceInfo(apiCode);

  const { url, verb, body, params: query, callbackName, apiType } = toJson(ret.data);

  let api = url;
  const querys = QueryString.parse(query || '', {
    ignoreQueryPrefix: true,
  });

  let bodys = QueryString.parse(body || '', {
    ignoreQueryPrefix: true,
  });

  if (isCustom || apiType === ApiType.FILE_UPLOAD) return { url, querys, bodys, verb };
  const fields = Object.keys(querys).join(',');

  const bodyFields = Object.keys(bodys).join(',');

  const queryCoverFields = getRowKeys(fields, params);

  const bodyoverFields = getRowKeys(bodyFields, params);

  if (verb === 'POST') {
    const res = {
      ...querys,
      ...queryCoverFields,
    };
    api += QueryString.stringify(res, { addQueryPrefix: true });
    bodys = Object.assign({}, bodys, params);
  } else {
    bodys = Object.assign({}, bodys, querys, queryCoverFields, bodyoverFields, params);
  }

  if (apiType === ApiType.FILE_EXPORT) return { api, bodys, verb };

  const res = await defHttp[verb.toLowerCase()]({
    url: api,
    params: bodys,
  });

  const fnName = callbackName || callbackFn;
  callbacks[fnName] && callbacks[fnName](res);
  return res;
};

export function getCustomCallBackData(callbackName: string) {
  let fn;
  if (!callbackName) return;
  for (const i in callbackFn) {
    if (i === callbackName) {
      fn = callbackFn[i];
      break;
    }
  }
  return fn && fn();
}
const frontApi = {
  downloadByApiUrl,
  getRealApi,
  exportFile,
};

// 自定义组件内相关方法
const customComponentApi = {};

interface CustomObjParam {
  labelField: string | null | undefined;
  value: any;
}

export function getRowKeys(key: string, record: Recordable, customObj?: CustomObjParam) {
  if (isNullOrUnDef(key)) return {};
  const keys = key.split(',');
  const params = {};
  for (const key of keys) {
    if (key && record[key]) {
      if (customObj && customObj.labelField === key) {
        params[key] = customObj.value;
      } else {
        params[key] = record[key];
      }
    }
  }
  return params;
}

// 增加删除类型
export async function handleBatchDel(
  { moduleId, primaryKey, tableModelId }: Recordable,
  tableFn: TableActionType,
) {
  const ids: ModelIds = { moduleId, modelId: tableModelId };

  const res = tableFn.getSelectRows();
  if (!res.length) {
    createMessage.warning('未选择数据');
    return;
  }
  createConfirm({
    iconType: 'warning',
    title: '提示',
    content: '是否批量删除选择的数据',
    onOk: async () => {
      const data = res.map((record) => {
        return getRowKeys(primaryKey, record);
      });
      try {
        await commonBatchApi(ids, { idList: data });
        tableFn.reload && tableFn.reload();
        createMessage.success('操作成功');
      } catch (e) {
        throw e;
      }
    },
  });
}

export async function handleImportApi(btnItem, callbacks) {
  let data = undefined;
  if (btnItem.record) {
    data = btnItem.record;
  }
  const { url, querys, bodys } = await getRealApi({
    params: data,
    apiCode: btnItem.apiCode,
    isCustom: true,
  });

  return async (
    params: UploadFileParams,
    onUploadProgress: (progressEvent: ProgressEvent) => void,
  ) => {
    const ret = await defHttp.uploadFile<any>(
      {
        url,
        onUploadProgress,
      },
      { ...querys, ...bodys, ...params, data },
    );
    callbacks.reload && callbacks.reload();

    return ret;
  };
}

export async function customFnForApi(btnItem, callbacks) {
  customRowFnForApi(btnItem, {}, callbacks);
}

// 自定义打开弹窗
function selfFunction(params, btnItem, data) {
  // btnItem
  const record = mergeBtnParams(btnItem);

  !btnItem.record && (btnItem.record = record);
  btnItem?.openModel(true, { paramsObj: params, btnItem, data });
}

export function customComponentAboutFn(btnItem: Indexable, data: ActionItemModel | Indexable = {}) {
  const params = toJson(btnItem.params);
  selfFunction(params, btnItem, data);
  const customComponentFn = customComponentApi[btnItem.api];
  if (customComponentFn) {
    customComponentFn(params, btnItem, data);
  }
}

// =========== 表格行按钮方法 ============
function updateModalConfig(model) {
  let count = 3;
  const timer = setInterval(() => {
    count--;
    model.update({
      okText: `确定（${count}）`,
    });
    if (!count) {
      clearInterval(timer);
      model.update({
        okText: `确定`,
        okButtonProps: {
          disabled: false,
        },
      });
      return;
    }
  }, 1000);
}

export function commonDel({ source, ids, params }, callback) {
  async function commonRemoveApiFn() {
    await commonRemoveApi(ids, params, source.deleteDialogType == 1 ? 'modal' : 'msg');
    createMessage.success('操作成功');
    callback && callback();
  }
  return {
    ...source,
    color: 'error',
    popConfirm: {
      title: '是否确认删除',
      placement: 'left',
      async confirm() {
        commonRemoveApiFn();
      },
    },

    showModalConfirm: {
      title: h(
        'span',
        {
          style: {
            fontWeight: 'bold',
          },
        },
        '删除提示',
      ),
      icon: h(ExclamationCircleFilled),
      content: source.confirmMsg || '所删除的内容包含了重要内容，请谨慎删除!',
      okText: '确定（3）',
      cancelText: '取消',
      maskClosable: false,
      okButtonProps: {
        disabled: true,
      },
      destroyOnClose: true,
      // 更新Modal数据
      update: (model: ModalFunc) => updateModalConfig(model),
      async onOk() {
        commonRemoveApiFn();
      },
    },
  };
}

// 流程单个删除
export function commonFlowDel(type: DelBatchType, { source, record }, callback) {
  async function removeApi() {
    try {
      switch (type) {
        case DelBatchType.FLOWDELETE:
          const { WorkItemID } = record;
          const params = { workItemIdList: [WorkItemID] };
          await deleteFlowProcessApi(params, source.deleteDialogType == 1 ? 'modal' : 'msg');
          break;
        case DelBatchType.FLOWHANDROUNDDELETE:
          const { ID } = record;
          const handparams = { transferWorkItemIdList: [ID] };
          await deleteTransferFlowApi(handparams, source.deleteDialogType == 1 ? 'modal' : 'msg');
          break;
      }
      createMessage.success('操作成功');
      callback && callback();
    } catch (e) {
      throw e;
    }
  }

  return {
    ...source,
    color: 'error',
    popConfirm: {
      title: '是否确认删除',
      placement: 'left',
      async confirm() {
        removeApi();
      },
    },
    showModalConfirm: {
      title: h(
        'span',
        {
          style: {
            fontWeight: 'bold',
          },
        },
        '删除提示',
      ),
      icon: h(ExclamationCircleFilled),
      content: source.confirmMsg || '所删除的内容包含了重要内容，请谨慎删除!',
      okText: '确定（3）',
      cancelText: '取消',
      maskClosable: false,
      okButtonProps: {
        disabled: true,
      },
      destroyOnClose: true,
      // 更新Modal数据
      update: (model: ModalFunc) => updateModalConfig(model),
      async onOk() {
        removeApi();
      },
    },
  };
}
export const mergeBtnParams = (btnItem: Indexable = {}, record: Indexable = {}) => {
  const { complexParams = {}, tableModelId, moduleId } = btnItem._comParams || {};
  const { windowQuery, windowParam } = complexParams;
  const btnParams = toJson(btnItem.params);
  const params = Object.assign(
    { tableModelId, moduleId },
    windowQuery,
    windowParam,
    btnParams,
    record,
    {
      ...(record.record || {}),
    },
  );

  return params;
};

const btnEventFunction = (
  functionText: string,
  { params = {}, schema = {}, tableActionType, formActionType }: BtnEventContext,
) => {
  const fn = new Function(
    'context',
    'schema',
    'defHttp',
    `return (async function(context,schema,defHttp){${functionText}})(context,schema,defHttp)`,
  );

  const context = {
    parentParams: params,
    messageFn,
    tableActionType,
    formActionType,
    downloadByData,
    dayjs,
  };

  fn(context, schema, defHttp);
};

export async function customRowFnForApi(
  btnItem: Indexable,
  data: ActionItemModel | Indexable = {},
  callbacks: Indexable<Fn> = {},
) {
  const frontApiFn = frontApi[btnItem.api];

  const params = mergeBtnParams(btnItem, data);
  const funcParams: Indexable = {
    params,
    schema: btnItem,
  };

  if (btnItem.isForm) {
    funcParams.formActionType = callbacks;
  } else {
    funcParams.tableActionType = callbacks;
  }

  if (frontApiFn) {
    if (btnItem.function) {
      btnEventFunction(btnItem.function, funcParams);
      return;
    } else if (btnItem.apiCode) {
      frontApiFn({ params, apiCode: btnItem.apiCode, callbacks });
      return;
    }

    frontApiFn(params, btnItem, data);
    return;
  }

  if (btnItem.function) {
    btnEventFunction(btnItem.function, funcParams);
  } else if (btnItem.apiCode) {
    await getRealApi({ params, apiCode: btnItem.apiCode, callbacks });
  }
}

async function exportFile({ params, apiCode }) {
  const { api, bodys, verb } = await getRealApi({
    params,
    apiCode,
  });

  const res = await defHttp[verb.toLowerCase()](
    {
      url: api,
      responseType: 'arraybuffer',
      params: {
        ...bodys,
      },
    },
    { isTransformResponse: false, isReturnNativeResponse: true },
  );
  const { data, headers, status } = res;

  if (status !== 200) {
    createMessage.error('系统错误');
    return;
  }

  downloadByData(data, headers.filename || `temp_${Date.now()}.xlsx`);
}

// 通用公共下载
export const commonDownLoad = async (data) => {
  const params = toJson(data.params);

  const dynamicParam = getRowKeys(data.dynamicParams, data.record);

  const fileList: object[] = [];
  Object.values(dynamicParam).forEach((i) => {
    fileList.push(...toJson(i));
  });

  await commonDownFile({
    ...params,
    file: JSON.stringify(fileList),
  });
};
